<template>
  <div class="virtual-lab-container" :class="{ shaking: isShaking }" ref="componentRoot">
    <div v-if="isCracked" class="crack-overlay">
      <svg width="100%" height="100%" viewBox="0 0 500 500" preserveAspectRatio="none">
        <defs>
          <filter id="roughness" x="-50%" y="-50%" width="200%" height="200%">
            <feTurbulence baseFrequency="0.02" numOctaves="3" stitchTiles="stitch" type="fractalNoise" result="turbulence" />
            <feDisplacementMap in="SourceGraphic" in2="turbulence" scale="5" xChannelSelector="R" yChannelSelector="G" />
          </filter>
        </defs>
        <path v-for="(crack, index) in cracks" :key="index" :d="crack" stroke="rgba(0,0,0,0.4)" stroke-width="2" fill="transparent" :style="{ filter: 'url(#roughness)' }" />
        <circle v-for="(fragment, index) in fragments" :key="'frag-' + index" :cx="fragment.x" :cy="fragment.y" :r="fragment.size" fill="rgba(0,0,0,0.3)" />
      </svg>
    </div>

    <h2 class="lab-title">黑火药爆炸模拟 (手动混合)</h2>

    <div class="scene-wrapper">
      <div class="reagent-shelf">
        <div class="shelf-title">实验材料</div>
        <div class="reagent-source" v-if="!materialsInDish.sulfur" draggable="true" @dragstart="handleDragStart('sulfur')">
          <div class="reagent-icon sulfur"></div>
          <span>硫磺粉</span>
        </div>
        <div class="reagent-source" v-if="!materialsInDish.saltpeter" draggable="true" @dragstart="handleDragStart('saltpeter')">
          <div class="reagent-icon saltpeter"></div>
          <span>硝石粉</span>
        </div>
        <div class="reagent-source" v-if="!materialsInDish.charcoal" draggable="true" @dragstart="handleDragStart('charcoal')">
          <div class="reagent-icon charcoal"></div>
          <span>木炭粉</span>
        </div>
        <div v-if="allMaterialsMixed" class="shelf-empty-message">
          材料已混合
        </div>
      </div>

      <div class="experiment-scene">
        <div class="combustion-dish" @dragover.prevent @drop.prevent="handleDrop">
          <div class="mixture-pile" v-if="!isExploding">
            <div class="mixture-layer sulfur" :class="{ 'visible': materialsInDish.sulfur }"></div>
            <div class="mixture-layer saltpeter" :class="{ 'visible': materialsInDish.saltpeter }"></div>
            <div class="mixture-layer charcoal" :class="{ 'visible': materialsInDish.charcoal }"></div>
          </div>

          <div class="igniter" v-if="experimentState === 'ready_to_ignite'" @click="triggerReaction" title="点燃混合物">
            🔥
          </div>

          <div class="ignition-point" v-if="isIgniting"></div>

          <div v-if="isExploding" class="explosion-container">
            <div class="flash"></div>
            <div class="shockwave"></div>
            <div class="smoke"></div>
            <div class="sparks">
              <div class="spark" v-for="i in 20" :key="i" :style="getParticleStyle(180, 2)"></div>
            </div>
            <div class="debris-container">
              <div class="debris" v-for="i in 15" :key="i" :style="getParticleStyle(250, 3)"></div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="info-panel">
      <p><strong>实验步骤:</strong> {{ phenomenonText }}</p>
      <p>\[2KNO_3 + S + 3C \rightarrow K_2S + N_2\uparrow + 3CO_2\uparrow\]</p>
      <button @click="resetExperiment" :disabled="experimentState === 'running'">
        重置实验
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue';

// --- 引用组件根元素 ---
const componentRoot = ref(null);

// --- 动态加载与卸载 KaTeX 的逻辑 ---
const KATE_CSS_ID = 'katex-css-dynamic';
const KATE_JS_ID = 'katex-js-dynamic';
const KATE_AUTO_RENDER_ID = 'katex-auto-render-dynamic';

onMounted(() => {
  // --- 加载 CSS ---
  if (!document.getElementById(KATE_CSS_ID)) {
    const cssLink = document.createElement('link');
    cssLink.id = KATE_CSS_ID;
    cssLink.rel = 'stylesheet';
    cssLink.href = 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css';
    document.head.appendChild(cssLink);
  }

  // --- 按顺序加载 JS ---
  if (!document.getElementById(KATE_JS_ID)) {
    const katexScript = document.createElement('script');
    katexScript.id = KATE_JS_ID;
    katexScript.src = 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js';
    katexScript.defer = true;
    document.head.appendChild(katexScript);

    katexScript.onload = () => {
      if (!document.getElementById(KATE_AUTO_RENDER_ID)) {
        const autoRenderScript = document.createElement('script');
        autoRenderScript.id = KATE_AUTO_RENDER_ID;
        autoRenderScript.src = 'https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js';
        autoRenderScript.defer = true;
        document.head.appendChild(autoRenderScript);

        autoRenderScript.onload = () => {
          if (window.renderMathInElement && componentRoot.value) {
            window.renderMathInElement(componentRoot.value, {
              delimiters: [
                { left: '$$', right: '$$', display: true },
                { left: '\\[', right: '\\]', display: true },
                { left: '$', right: '$', display: false },
                { left: '\\(', right: '\\)', display: false }
              ],
              throwOnError: false
            });
          }
        };
      }
    };
  }
});

onUnmounted(() => {
  // --- 组件卸载时，清理添加的link和script ---
  const css = document.getElementById(KATE_CSS_ID);
  if (css) css.remove();
  const coreJs = document.getElementById(KATE_JS_ID);
  if (coreJs) coreJs.remove();
  const autoRenderJs = document.getElementById(KATE_AUTO_RENDER_ID);
  if (autoRenderJs) autoRenderJs.remove();
});


// --- 实验核心逻辑 ---

// --- 状态管理 ---
const experimentState = ref('idle'); // 'idle', 'mixing', 'ready_to_ignite', 'running', 'finished'
const phenomenonText = ref('请将三种材料拖入燃烧皿中混合。');
const draggingMaterial = ref(null);
const materialsInDish = reactive({
  sulfur: false,
  saltpeter: false,
  charcoal: false,
});

// --- 现象控制 ---
const isIgniting = ref(false);
const isExploding = ref(false);
const isShaking = ref(false);
const isCracked = ref(false);
const cracks = ref([]);
const fragments = ref([]);

// --- 计算属性 ---
const allMaterialsMixed = computed(() => {
  return materialsInDish.sulfur && materialsInDish.saltpeter && materialsInDish.charcoal;
});

// --- 辅助函数 ---
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

// --- 拖拽逻辑 ---
function handleDragStart(material) {
  if (experimentState.value === 'idle' || experimentState.value === 'mixing') {
    draggingMaterial.value = material;
  } else {
    event.preventDefault();
  }
}

function handleDrop() {
  if (draggingMaterial.value && !materialsInDish[draggingMaterial.value]) {
    experimentState.value = 'mixing';
    materialsInDish[draggingMaterial.value] = true;
    draggingMaterial.value = null;

    if (allMaterialsMixed.value) {
      phenomenonText.value = '材料已混合完毕！请点击火焰点燃。';
      experimentState.value = 'ready_to_ignite'; // **状态转移**
    } else {
      const remaining = Object.keys(materialsInDish).filter(k => !materialsInDish[k]).length;
      phenomenonText.value = `混合成功！请继续添加剩余的 ${remaining} 种材料。`;
    }
  }
}

// --- 屏幕碎裂效果生成函数 ---
function generateCracks() {
  const numCracks = 12;
  const maxDeviation = 40;
  const maxLength = 180;
  const crackPaths = [];
  const impactRadius = 100;
  const angleOffset = Math.random() * Math.PI * 2;
  const distanceOffset = Math.random() * impactRadius;
  const centerX = 250 + Math.cos(angleOffset) * distanceOffset;
  const centerY = 250 + Math.sin(angleOffset) * distanceOffset;
  for (let i = 0; i < numCracks; i++) {
    const angle = Math.random() * Math.PI * 2;
    const length = Math.random() * maxLength + 80;
    const endX = centerX + Math.cos(angle) * length;
    const endY = centerY + Math.sin(angle) * length;
    let path = `M${centerX.toFixed(2)},${centerY.toFixed(2)}`;
    const steps = Math.floor(Math.random() * 5) + 4;
    for (let j = 1; j < steps; j++) {
      const fraction = j / steps;
      const midX = centerX + (endX - centerX) * fraction + (Math.random() * 2 - 1) * maxDeviation;
      const midY = centerY + (endY - centerY) * fraction + (Math.random() * 2 - 1) * maxDeviation;
      path += ` L${midX.toFixed(2)},${midY.toFixed(2)}`;
    }
    path += ` L${endX.toFixed(2)},${endY.toFixed(2)}`;
    crackPaths.push(path);
  }
  cracks.value = crackPaths;
  const numFragments = 25;
  const fragList = [];
  for (let i = 0; i < numFragments; i++) {
    fragList.push({
      x: Math.random() * 500,
      y: Math.random() * 500,
      size: Math.random() * 2.5 + 1,
    });
  }
  fragments.value = fragList;
}

// 组件挂载时先生成一次裂痕数据
onMounted(generateCracks);

// --- 主要实验逻辑 ---
async function triggerReaction() {
  if (experimentState.value !== 'ready_to_ignite') return;

  experimentState.value = 'running'; // **状态转移**
  phenomenonText.value = '准备点燃...';
  isIgniting.value = true;
  await delay(1500);

  phenomenonText.value = '点燃！发生剧烈爆炸，产生大量光和热！';
  isIgniting.value = false;
  isExploding.value = true;

  isShaking.value = true;
  await delay(150);
  isCracked.value = true;

  await delay(300);
  isShaking.value = false;

  await delay(2550);

  phenomenonText.value = '爆炸结束。实验危险，切勿模仿！';
  isExploding.value = false;
  experimentState.value = 'finished'; // **状态转移**
}

// --- 重置实验 ---
function resetExperiment() {
  experimentState.value = 'idle'; // **状态转移**
  phenomenonText.value = '请将三种材料拖入燃烧皿中混合。';
  Object.keys(materialsInDish).forEach(key => {
    materialsInDish[key] = false;
  });
  isIgniting.value = false;
  isExploding.value = false;
  isShaking.value = false;
  isCracked.value = false;
  generateCracks();
}

// --- 动态样式 (粒子效果) ---
const getParticleStyle = (maxDist, duration) => {
  const angle = Math.random() * 360;
  const dist = Math.random() * maxDist + 50;
  return {
    '--angle': `${angle}deg`,
    '--dist': `${dist}px`,
    'animation-duration': `${Math.random() * 0.5 + duration}s`,
    'animation-delay': `${Math.random() * 0.2}s`,
  };
};

</script>

<style scoped>
/* 所有样式保持不变，此处省略以节约篇幅 */
/* --- 基础布局和样式 --- */
.virtual-lab-container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #fdfdfd;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  padding: 20px;
  overflow: hidden;
  transition: transform 0.1s;
  position: relative;
}

/* 应用震动动画 */
.virtual-lab-container.shaking {
  animation: screen-shake 0.15s 3;
}

.lab-title {
  text-align: center;
  color: #334e68;
  margin-top: 0;
}

.scene-wrapper {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 40px;
  flex-grow: 1;
}

/* --- 1. 试剂架 --- */
.reagent-shelf {
  flex-shrink: 0;
  width: 150px;
  padding: 15px;
  background-color: #f0f4f8;
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  border: 1px solid #d1d9e6;
}

.shelf-title {
  font-weight: bold;
  color: #486581;
  font-size: 16px;
  margin-bottom: 10px;
}

.reagent-source {
  text-align: center;
  cursor: grab;
}

.reagent-source:active {
  cursor: grabbing;
}

.reagent-icon {
  width: 50px;
  height: 50px;
  margin: 0 auto 5px;
  border-radius: 50%;
  border: 3px solid white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.reagent-icon.sulfur {
  background-color: #f7e736;
}

.reagent-icon.saltpeter {
  background-color: #f0f0f0;
  border: 3px solid #e0e0e0;
}

.reagent-icon.charcoal {
  background-color: #444;
}

.shelf-empty-message {
  color: #829ab1;
  font-style: italic;
}

/* --- 2. 实验场景 --- */
.experiment-scene {
  position: relative;
  width: 250px;
  height: 250px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.combustion-dish {
  width: 200px;
  height: 80px;
  border: 4px solid #829ab1;
  border-radius: 50% / 100% 100% 20% 20%;
  background-color: #e0e6ed;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
}

.mixture-pile {
  position: absolute;
  bottom: 4px;
  width: 100px;
  height: 60px;
}

.mixture-layer {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-radius: 50%;
  opacity: 0;
  transition: width 0.5s, height 0.5s, opacity 0.5s;
}

.mixture-layer.sulfur {
  background-color: rgba(247, 231, 54, 0.7);
}

.mixture-layer.saltpeter {
  background-color: rgba(240, 240, 240, 0.8);
}

.mixture-layer.charcoal {
  background-color: rgba(68, 68, 68, 0.6);
}

.mixture-layer.sulfur.visible {
  width: 80px;
  height: 15px;
  opacity: 1;
}

.mixture-layer.saltpeter.visible {
  width: 90px;
  height: 25px;
  opacity: 1;
  bottom: 5px;
}

.mixture-layer.charcoal.visible {
  width: 100px;
  height: 20px;
  opacity: 1;
  bottom: 15px;
}

.igniter {
  position: absolute;
  top: -30px;
  font-size: 40px;
  cursor: pointer;
  transition: transform 0.2s ease;
  animation: float 1.5s infinite alternate ease-in-out;
}

.igniter:hover {
  transform: scale(1.2);
}

.ignition-point {
  position: absolute;
  width: 20px;
  height: 20px;
  background: radial-gradient(circle, #ffeb3b, #ffc107, rgba(255, 193, 7, 0));
  border-radius: 50%;
  animation: ignition-flicker 0.5s infinite;
}

/* --- 3. 信息面板 --- */
.info-panel {
  margin-top: 20px;
  padding: 15px;
  text-align: center;
  background-color: #f0f4f8;
  border-radius: 8px;
}

.info-panel p {
  margin: 8px 0;
  color: #486581;
}

.info-panel button {
  margin-top: 10px;
  padding: 10px 25px;
  border: none;
  border-radius: 6px;
  background-color: #3498db;
  color: white;
  cursor: pointer;
  transition: background-color 0.3s;
}

.info-panel button:disabled {
  background-color: #a0a0a0;
  cursor: not-allowed;
}

.info-panel button:hover:not(:disabled) {
  background-color: #2980b9;
}

/* --- 动画效果 --- */

/* 碎屏效果 */
.crack-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 100;
  opacity: 0;
  animation: crack-appear 0.2s forwards;
}

@keyframes crack-appear {
  from {
    opacity: 0;
  }
  to {
    opacity: 0.7;
  }
}

/* 屏幕震动动画 */
@keyframes screen-shake {
  0%,
  100% {
    transform: translate(0, 0);
  }
  25% {
    transform: translate(-6px, 6px) rotate(-0.5deg);
  }
  50% {
    transform: translate(6px, -6px) rotate(0.5deg);
  }
  75% {
    transform: translate(-6px, -6px) rotate(-0.5deg);
  }
}

@keyframes float {
  from {
    transform: translateY(0px);
  }
  to {
    transform: translateY(-10px);
  }
}

@keyframes ignition-flicker {
  0%,
  100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.2);
    opacity: 0.8;
  }
}

.explosion-container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.flash {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 500px;
  height: 500px;
  background: radial-gradient(circle, white 5%, rgba(255, 251, 206, 0.8) 30%, rgba(255, 165, 0, 0) 70%);
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
  animation: flash-bang 0.5s ease-out forwards;
}

.shockwave {
  position: absolute;
  top: 50%;
  left: 50%;
  border-radius: 50%;
  border: 5px solid rgba(255, 224, 130, 0.7);
  transform: translate(-50%, -50%);
  opacity: 0;
  animation: shockwave-expand 1.5s ease-out 0.1s forwards;
}

.smoke {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 250px;
  height: 250px;
  background: radial-gradient(circle, rgba(90, 90, 90, 0.8), rgba(50, 50, 50, 0) 70%);
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
  animation: smoke-puff 3s ease-out 0.3s forwards;
}

.sparks,
.debris-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.spark,
.debris {
  position: absolute;
  top: 50%;
  left: 50%;
  opacity: 0;
  animation-name: fly-out;
  animation-timing-function: ease-out;
  animation-fill-mode: forwards;
}

.spark {
  width: 6px;
  height: 6px;
  background-color: #ffd700;
  border-radius: 50%;
}

.debris {
  width: 4px;
  height: 4px;
  background: #3d3d3d;
}

@keyframes flash-bang {
  from {
    transform: translate(-50%, -50%) scale(0);
    opacity: 1;
  }
  to {
    transform: translate(-50%, -50%) scale(1.5);
    opacity: 0;
  }
}

@keyframes shockwave-expand {
  from {
    width: 50px;
    height: 50px;
    opacity: 1;
  }
  to {
    width: 600px;
    height: 600px;
    opacity: 0;
  }
}

@keyframes smoke-puff {
  from {
    transform: translate(-50%, -50%) scale(0);
    opacity: 0.9;
  }
  to {
    transform: translate(-50%, -60%) scale(2.5);
    opacity: 0;
  }
}

@keyframes fly-out {
  from {
    transform: rotate(var(--angle)) translateY(0px) scale(1);
    opacity: 1;
  }
  to {
    transform: rotate(var(--angle)) translateY(var(--dist)) scale(0);
    opacity: 0;
  }
}
</style>